#include "serial.h"

void serialInit(uint8_t baudrate, uint8_t mode, uint8_t parity, uint8_t stop, uint8_t charsize){
  /**
   * Only configure module when there are no ongoing transmissions
   * TxCn <= should be completed
   * RxCn <= should not indicate unread data in buffer
   */
  // check for ideal init conditions
  /*
  // set baudrate
  setUSARTBaudrate(baudrate);
  // set mode of operation
  setUSARTModeOfOperation(mode);
  // set frame format
  setUSARTParity(parity);
  setUSARTStopBits(stop);
  setUSARTCharSize(charsize);
  // enable Tx and Rx
  UCSR0B |= (_BV(TXEN0) || _BV(RXEN0));*/
}

void setUSARTModeOfOperation(uint8_t mode){
  switch(mode){
  case MODEASYNC:
    // UMSELn = 0 asynchronous mode
    // clear UCPOLn
    UCSR0C &= ~(_BV(UMSEL01) || _BV(UMSEL00) || _BV(UCPOL0));
  case MODESYNC:
    // UMSELn = 1 synchronous mode
    UCSR0C &= ~_BV(UMSEL01);
    UCSR0C |= _BV(UMSEL00);
  }
}

void setUSARTParity(uint8_t mode){
  switch(mode){
  case PARITYEVEN:
    // set 01
    UCSR0C &= ~_BV(UPM00);
    UCSR0C |= _BV(UPM01);
  case PARITYODD:
    // set 11
    UCSR0C |= (_BV(UPM00) || _BV(UPM01));
  default:
    // set 00
    UCSR0C &= ~(_BV(UPM00) || _BV(UPM01));
  }
}

void setUSARTStopBits(uint8_t bits){
  if(bits == 0){
    UCSR0C &= ~_BV(USBS0);
  }else{
    UCSR0C |= _BV(USBS0);
  }
}

void setUSARTCharSize(uint8_t size){
  // TODO: build-in other cases
  switch(size){
  case 5:
    // set 000
    UCSR0C &= ~(_BV(UCSZ00) || _BV(UCSZ01));
    UCSR0B &= ~_BV(UCSZ02);
  default:
    // 8-bit is default
    // set 011
    UCSR0C |= (_BV(UCSZ00) || _BV(UCSZ01));
    UCSR0B &= ~_BV(UCSZ02);
  }
}

uint16_t calcUSARTBaudRate(uint8_t baudrate){
  /**
   *  baudrate = fck/16*(UBR + 1)
   *  UBR = fck/(16*baudrate) - 1
   **/
  return( (FREQ_MHz/16*baudrate) - 1);
}

void setUSARTBaudRate(uint8_t baudrate){
  uint16_t REG = calcUSARTBaudRate(baudrate); 
  // write the value to the registers
  UBRR0H = REG>>8;
  UBRR0L = REG;
}

void putUSART(uint8_t bitword, uint8_t timeout){
  /**
   * transmission initiated by writing data to UDR
   * if (UDRE || USR) data is send from data reg to shift reg
   * if (TxCn || USR) data is is transmitted and new data can be send
   * if (TxEN || UCR) transmit mode is enabled
   */
  uint8_t x;
  for(x = 0; x++; x < timeout){
    // wait until module is ready for write
    /*
    if((_BV(UDRE0) && USR0A)){
      UDR0 = bitword;
      break;
      }*/
  }
}

/*void sendUSART(uint8_t string){
  // handle the string as pointer
  uint8_t x = 0;
  while(string[x]){
    putUSART(string[x], 100);
    if(string[x] = '\0'){
      break;
    }
    x++;
  }
  }*/

/**
 * Reads data from the UART module
 * @param maxLen maximum length of the string to be read
 */
void readUSART(uint8_t maxLen){
  // reads data
}
